package org.persistente.xml;

import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author philipe
 */
public class XmlBuilder {

    String root;
    Map<String, String> attributes;
    Map<String, Object> compositeAttibutes;

    public XmlBuilder(String root) {
        this.root = root;
        this.attributes = new HashMap<String, String>();
        this.compositeAttibutes = new HashMap<String, Object>();
    }

    public void add(String attribute, String value) {
        attributes.put(attribute, value);
    }

    public void add(String attribute, int value) {
        add(attribute, String.valueOf(value));
    }

    public void add(String attribute, double value) {
        add(attribute, String.valueOf(value));
    }
    private static DecimalFormat decimalFormat;

    static {
        DecimalFormatSymbols dfs = new DecimalFormatSymbols();
        dfs.setDecimalSeparator('.');
        dfs.setGroupingSeparator('\0');
        decimalFormat = new DecimalFormat("#.###############", dfs);
    }

    public void add(String attribute, Object value) {
        if (value != null) {
            Class c = value.getClass();
            if (c.isArray()) {
                add(attribute, toXmlNode((Object[])value));
            } else if (c == double.class
                    || c == float.class
                    || c == Float.class
                    || c == Double.class) {

                add(attribute, decimalFormat.format(value));

            } else if (c == int.class
                    || c == Integer.class
                    || c == long.class
                    || c == Long.class
                    || c == char.class
                    || c == Character.class
                    || c == java.sql.Date.class
                    || c == java.util.Date.class
                    || c == String.class
                    || c == Boolean.class
                    || c == boolean.class
                    || c.isArray()) {
                add(attribute, String.valueOf(value));
            } else if (c == Timestamp.class) {
                SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Timestamp ts = (Timestamp) value;
                add(attribute, f.format(new java.util.Date(ts.getTime())));
            } else {
                compositeAttibutes.put(attribute, value);
            }
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();

        sb.append("<").append(root).append(">\n");

        for (Map.Entry<String, String> en : attributes.entrySet()) {
            sb.append("\t<").append(en.getKey()).append(">");
            sb.append(en.getValue());
            sb.append("</").append(en.getKey()).append(">\n");
        }
        for (Map.Entry<String, Object> en : compositeAttibutes.entrySet()) {
            sb.append(toXmlNode(en.getValue()));
        }

        sb.append("</").append(root).append(">\n");
        return sb.toString();
    }

    public static String toXmlNode(Object object) {
        Class cl = object.getClass();

        String root = transform(cl.getSimpleName());
        XmlBuilder xml = new XmlBuilder(root);
        for (Field field : cl.getFields()) {
            try {
                String name = CamelCase.fromCamelCase(field.getName(), "-");
                Object value = field.get(object);
                xml.add(name, value);
            } catch (Exception ex) {
                ex.printStackTrace();
                throw new RuntimeException("Erro inesperado!", ex);
            }

        }

        return xml.toString();
    }

    public static String toXmlNode(Object[] array) {
        StringBuilder sb = new StringBuilder();
        for (Object obj : array) {
            sb.append(toXmlNode(obj));
        }
        return sb.toString();
    }

    public static String toXml(Object object) {


        String encoding = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";

        return encoding + toXmlNode(object);
    }

    private static String transform(String s) {
        return new CamelCase(s).separateWith("-").toLowerCase();
    }
}
